/** @file
 *
 *  Copyright (c) 2021 Rockchip Electronics Co., Ltd.
 *  Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
 *
 *  SPDX-License-Identifier: BSD-2-Clause-Patent
 *
 **/

#ifndef __RK_I2C_DXE_H__
#define __RK_I2C_DXE_H__

#include <Uefi.h>

#define I2C_PERIPHERAL_SIZE  0x1000

#define I2C_SLAVE_ADDR      0x00
#define I2C_EXT_SLAVE_ADDR  0x10
#define I2C_DATA            0x04

#define I2C_CONTROL        0x08
#define I2C_CONTROL_ACK    (1 << 2)
#define I2C_CONTROL_IFLG   (1 << 3)
#define I2C_CONTROL_STOP   (1 << 4)
#define I2C_CONTROL_START  (1 << 5)
#define I2C_CONTROL_I2CEN  (1 << 6)
#define I2C_CONTROL_INTEN  (1 << 7)

#define I2C_STATUS                0x0c
#define I2C_STATUS_START          0x08
#define I2C_STATUS_RPTD_START     0x10
#define I2C_STATUS_ADDR_W_ACK     0x18
#define I2C_STATUS_DATA_WR_ACK    0x28
#define I2C_STATUS_ADDR_R_ACK     0x40
#define I2C_STATUS_DATA_RD_ACK    0x50
#define I2C_STATUS_DATA_RD_NOACK  0x58

#define I2C_BAUD_RATE_REG  0x0c
#define I2C_BAUD_RATE_PARAM(M, N)   ((((M) << 3) | ((N) & 0x7)) & 0x7f)
#define I2C_BAUD_RATE_RAW(C, M, N)  ((C)/((10*(M+1))<<(N+1)))
#define I2C_M_FROM_BAUD(baud)       (((baud) >> 3) & 0xf)
#define I2C_N_FROM_BAUD(baud)       ((baud) & 0x7)

#define I2C_SOFT_RESET        0x1c
#define I2C_TRANSFER_TIMEOUT  10000
#define I2C_READY_TIMEOUT     100

#define I2C_UNKNOWN  0x0
#define I2C_SLOW     0x1
#define I2C_FAST     0x2
#define I2C_FASTEST  0x3

/* rk i2c fifo max transfer bytes */
#define RK_I2C_FIFO_SIZE  32

/* rk i2c device register size */
#define RK_I2C_REGISTER_SIZE  3

/* i2c timerout */
#define I2C_TIMEOUT_US   100000         // 100000us = 100ms
#define I2C_RETRY_COUNT  3

#define I2C_ADAP_SEL_BIT(nr)   ((nr) + 11)
#define I2C_ADAP_SEL_MASK(nr)  ((nr) + 27)

#define RK_CEIL(x, y) \
        ({ unsigned long __x = (x), __y = (y); (__x + __y - 1) / __y; })

/* Control register */
#define I2C_CON     0x000
#define I2C_CON_EN  (1 << 0)
#define I2C_CON_MOD(mod)  ((mod) << 1)
#define I2C_MODE_TX   0x00
#define I2C_MODE_TRX  0x01
#define I2C_MODE_RX   0x02
#define I2C_MODE_RRX  0x03
#define I2C_CON_MASK  (3 << 1)

#define I2C_CON_START    (1 << 3)
#define I2C_CON_STOP     (1 << 4)
#define I2C_CON_LASTACK  (1 << 5)
#define I2C_CON_ACTACK   (1 << 6)

#define I2C_CON_SDA_CFG(cfg)  ((cfg) << 8)
#define I2C_CON_STA_CFG(cfg)  ((cfg) << 12)
#define I2C_CON_STO_CFG(cfg)  ((cfg) << 14

#define I2C_CON_VERSION        (0xff << 16)
#define I2C_CON_VERSION_SHIFT  16

/* Clock dividor register */
#define I2C_CLKDIV              0x004
#define I2C_CLK_DIV_HIGH_SHIFT  16
#define I2C_CLKDIV_VAL(divl, divh)  (((divl) & 0xffff) | (((divh) << 16) & 0xffff0000))

/* the slave address accessed  for master rx mode */
#define I2C_MRXADDR  0x008
#define I2C_MRXADDR_SET(vld, addr)  (((vld) << 24) | (addr))

/* the slave register address accessed  for master rx mode */
#define I2C_MRXRADDR  0x00c
#define I2C_MRXRADDR_SET(vld, raddr)  (((vld) << 24) | (raddr))

/* master tx count */
#define I2C_MTXCNT  0x010

/* master rx count */
#define I2C_MRXCNT  0x014

/* interrupt enable register */
#define I2C_IEN        0x018
#define I2C_BTFIEN     (1 << 0)
#define I2C_BRFIEN     (1 << 1)
#define I2C_MBTFIEN    (1 << 2)
#define I2C_MBRFIEN    (1 << 3)
#define I2C_STARTIEN   (1 << 4)
#define I2C_STOPIEN    (1 << 5)
#define I2C_NAKRCVIEN  (1 << 6)

/* interrupt pending register */
#define I2C_IPD            0x01c
#define I2C_BTFIPD         (1 << 0)
#define I2C_BRFIPD         (1 << 1)
#define I2C_MBTFIPD        (1 << 2)
#define I2C_MBRFIPD        (1 << 3)
#define I2C_STARTIPD       (1 << 4)
#define I2C_STOPIPD        (1 << 5)
#define I2C_NAKRCVIPD      (1 << 6)
#define I2C_IPD_ALL_CLEAN  0x7f

/* finished count */
#define I2C_FCNT  0x020

/* I2C tx data register */
#define I2C_TXDATA_BASE  0X100

/* I2C rx data register */
#define I2C_RXDATA_BASE  0x200

#define I2C_GUID \
  { \
  0xadc1901b, 0xb83c, 0x4831, { 0x8f, 0x59, 0x70, 0x89, 0x8f, 0x26, 0x57, 0x1e } \
  }

#define I2C_MASTER_SIGNATURE  SIGNATURE_32 ('I', '2', 'C', 'M')

typedef struct {
  UINT32                                           Signature;
  EFI_HANDLE                                       Controller;
  UINTN                                            TclkFrequency;
  UINTN                                            BaseAddress;
  INTN                                             Bus;
  UINTN                                            Config;
  BOOLEAN                                          RuntimeSupport;
  EFI_I2C_MASTER_PROTOCOL                          I2cMaster;
  EFI_I2C_ENUMERATE_PROTOCOL                       I2cEnumerate;
  EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL    I2cBusConf;
  ROCKCHIP_I2C_MASTER_PROTOCOL                     RockchipI2cMaster;
} I2C_MASTER_CONTEXT;

#define I2C_SC_FROM_MASTER(a)     CR (a, I2C_MASTER_CONTEXT, I2cMaster, I2C_MASTER_SIGNATURE)
#define I2C_SC_FROM_ENUMERATE(a)  CR (a, I2C_MASTER_CONTEXT, I2cEnumerate, I2C_MASTER_SIGNATURE)
#define I2C_SC_FROM_BUSCONF(a)    CR (a, I2C_MASTER_CONTEXT, I2cBusConf, I2C_MASTER_SIGNATURE)

typedef struct {
  VENDOR_DEVICE_PATH          Guid;
  UINTN                       Instance;
  EFI_DEVICE_PATH_PROTOCOL    End;
} I2C_DEVICE_PATH;

typedef struct {
  UINT32    MinLowNs;
  UINT32    MinHighNs;
  UINT32    MaxRiseNs;
  UINT32    MaxFallNs;
} I2C_SPEC_VALUES;

typedef enum {
  RkI2cVersion0 = 0,
  RkI2cVersion1,
  RkI2cVersion5 = 5,
} I2C_VERSION;

STATIC
UINT32
I2cRead (
  IN I2C_MASTER_CONTEXT  *I2cMasterContext,
  IN UINTN               Off
  );

STATIC
EFI_STATUS
I2cWrite (
  IN I2C_MASTER_CONTEXT  *I2cMasterContext,
  IN UINTN               Off,
  IN UINT32              Val
  );

STATIC
CONST I2C_SPEC_VALUES *
I2cGetSpec (
  IN I2C_MASTER_CONTEXT  *I2cMasterContext,
  IN UINT32              Speed
  );

EFI_STATUS
EFIAPI
I2cInitialise (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  );

STATIC
VOID
I2cCalBaudRate (
  IN I2C_MASTER_CONTEXT  *I2cMasterContext,
  IN UINT32              Target,
  IN UINT32              ClkRate
  );

STATIC
EFI_STATUS
I2cAdapterBaudRate (
  IN I2C_MASTER_CONTEXT  *I2cMasterContext,
  IN CONST UINT32        Target,
  IN CONST UINT32        ClkRate
  );

STATIC
EFI_STATUS
EFIAPI
I2cSetBusFrequency (
  IN CONST EFI_I2C_MASTER_PROTOCOL  *This,
  IN OUT UINTN                      *BusClockHertz
  );

EFI_STATUS
EFIAPI
I2cReset (
  IN CONST EFI_I2C_MASTER_PROTOCOL  *This
  );

STATIC
VOID
I2cDisable (
  IN I2C_MASTER_CONTEXT  *I2cMasterContext
  );

STATIC
EFI_STATUS
I2cStartEnable (
  IN I2C_MASTER_CONTEXT  *I2cMasterContext,
  IN UINT32              Con,
  IN UINTN               Timeout
  );

STATIC
EFI_STATUS
I2cStop (
  IN I2C_MASTER_CONTEXT  *I2cMasterContext
  );

STATIC
EFI_STATUS
I2cReadOperation (
  IN I2C_MASTER_CONTEXT  *I2cMasterContext,
  IN UINTN               SlaveAddress,
  IN OUT UINT8           *buf,
  IN UINTN               len,
  IN OUT UINTN           *read,
  IN UINTN               last,
  IN UINTN               delay
  );

STATIC
EFI_STATUS
I2cWriteOperation (
  IN I2C_MASTER_CONTEXT  *I2cMasterContext,
  IN UINTN               SlaveAddress,
  IN OUT CONST UINT8     *buf,
  IN UINTN               len,
  IN OUT UINTN           *sent,
  IN UINTN               timeout
  );

STATIC
EFI_STATUS
EFIAPI
I2cStartRequest (
  IN CONST EFI_I2C_MASTER_PROTOCOL  *This,
  IN UINTN                          SlaveAddress,
  IN EFI_I2C_REQUEST_PACKET         *RequestPacket,
  IN EFI_EVENT                      Event      OPTIONAL,
  OUT EFI_STATUS                    *I2cStatus OPTIONAL
  );

STATIC
EFI_STATUS
EFIAPI
I2cEnumerate (
  IN CONST EFI_I2C_ENUMERATE_PROTOCOL  *This,
  IN OUT CONST EFI_I2C_DEVICE          **Device
  );

STATIC
EFI_STATUS
EFIAPI
I2cEnableConf (
  IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL  *This,
  IN UINTN                                                I2cBusConfiguration,
  IN EFI_EVENT                                            Event      OPTIONAL,
  IN EFI_STATUS                                           *I2cStatus OPTIONAL
  );

STATIC
I2C_VERSION
I2cGetVersion (
  IN I2C_MASTER_CONTEXT  *I2cMasterContext
  );

STATIC
VOID
I2cShowRegs (
  IN I2C_MASTER_CONTEXT  *I2cMasterContex
  );

#endif // __RK_I2C_DXE_H__
